<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one or more
  ~ contributor license agreements.  See the NOTICE file distributed with
  ~ this work for additional information regarding copyright ownership.
  ~ The ASF licenses this file to You under the Apache License, Version 2.0
  ~ (the "License"); you may not use this file except in compliance with
  ~ the License.  You may obtain a copy of the License at
  ~ 
  ~   http://www.apache.org/licenses/LICENSE-2.0
  ~ 
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
  
<template>
  <div
    ref="bottomPanel"
    class="log-panel">
    <div class="workbench-tabs">
      <div class="workbench-tab-wrapper">
        <div class="workbench-tab">
          <div
            :class="{active: scriptViewState.showPanel == 'progress'}"
            class="workbench-tab-item"
            @click="showPanelTab('progress')">
            <span>{{ $t('message.common.tabs.progress') }}</span>
          </div>
          <div
            v-if="script.result"
            :class="{active: scriptViewState.showPanel == 'result'}"
            class="workbench-tab-item"
            @click="showPanelTab('result')">
            <span>{{ $t('message.common.tabs.result') }}</span>
          </div>
          <div
            v-if="isLogShow"
            :class="{active: scriptViewState.showPanel == 'log'}"
            class="workbench-tab-item"
            @click="showPanelTab('log')">
            <span>{{ $t('message.common.tabs.log') }}</span>
          </div>
        </div>
        <!-- <div
          class="workbench-tab-button">
          <Icon
            type="ios-close"
            size="20"
            @click="closeConsole"></Icon>
        </div> -->
      </div>
      <div
        class="workbench-container">
        <we-progress
          v-if="scriptViewState.showPanel == 'progress'"
          :current="script.progress.current"
          :waiting-size="script.progress.waitingSize"
          :steps="script.steps"
          :status="script.status"
          :application="script.application"
          :progress-info="script.progress.progressInfo"
          :cost-time="script.progress.costTime"
          @open-panel="openPanel"
          :script-view-state="scriptViewState"/>
        <result
          v-if="scriptViewState.showPanel == 'result'"
          ref="result"
          :result="script.result"
          :script="script"
          :dispatch="dispatch"
          :getResultUrl="getResultUrl"
          :comData="comData"
          @on-analysis="openAnalysisTab"
          @on-set-change="changeResultSet"
          :script-view-state="scriptViewState"/>
        <log
          v-if="scriptViewState.showPanel == 'log'"
          :logs="script.log"
          :log-line="script.logLine"
          :script-view-state="scriptViewState"/>
      </div>
    </div>
  </div>
</template>
<script>
import api from '@/common/service/api';
import util from '@/common/util';
import storage from '@/common/helper/storage';
import {debounce, isUndefined, isEmpty, last} from 'lodash';
import {Script} from './modal.js';
import result from './result.vue';
import log from './log.vue';
import weProgress from './progress.vue';
import Execute from '@/common/service/execute';
import mixin from '@/common/service/mixin';
export default {
  components: {
    result,
    log,
    weProgress,
  },
  mixins: [mixin],
  props: {
    stop: {
      type: Boolean,
    },
    comData: {
      type: Object
    },
    heigth: {
      type: [String, Number]
    },
    dispatch: {
      type: Function,
      required: true
    },
    getResultUrl: {
      type: String,
      defalut: `filesystem`
    }
  },
  data() {
    return {
      execute: null,
      scriptViewState: {
        showPanel: 'progress',
        cacheLogScroll: 0,
        bottomContentHeight: '250'
      },
      isBottomPanelFull: false,
      isLogShow: false,
      localLog: {
        log: { all: '', error: '', warning: '', info: '' },
        logLine: 1,
      },
      script: {
        result: null,
        steps: [],
        progress: {},
        log: { all: '', error: '', warning: '', info: '' },
        logLine: 1,
        resultList: null,
      },
    }
  },
  watch: {
    stop(val, oldval) {
      if (oldval && this.execute) {
        // 先保留工作流页，应该会用到
        this.killExecute();
      }
    },
    'scriptResult.headRows': function() {
      if(this.visualShow === 'visual'){
        this.openAnalysisTab('table')
      }
    },
    executRun(val) {
      this.$emit('executRun', val)
    }
  },
  computed: {
    executRun() {
      return this.execute ? this.execute.run : false
    }
  },
  mounted() {
    this.scriptViewState.bottomContentHeight = this.heigth - 75;
  },
  methods: {
    killExecute(flag = false) {
      this.execute.trigger('stop');
      if (flag) {
        this.execute.trigger('kill');
      }
    },
    createScript() {
      this.script = new Script({
        id: this.comData.id,
        title: this.comData.name,
        scriptViewState: this.scriptViewState,
      });
    },
    createExecute(needQuery) {
      const data = {
        getResultUrl: this.getResultUrl,
        method: '/api/rest_j/v1/entrance/execute',
        websocketTag: this.comData.id,
        data: {
          executeApplicationName: null,
          executionCode: null,
          runType: this.comData.runType,
          params: null,
          postType: 'http',
          source: {
            scriptPath: null,
          },
          fromLine: this.script.logLine,
        },
      }
      this.execute = new Execute(data);
      if (needQuery) {
        this.queryState();
      }
    },
    queryState() {
      if (this.comData.execID) {
        const option = {
          taskID: this.comData.taskID,
          execID: this.comData.execID,
          isRestore: true,
          id: this.comData.id,
          nodeId: this.comData.key || undefined,
        }
        this.execute.halfExecute(option);
        this.monitoringData();
      }
    },
    monitoringData() {
      if (this.execute.taskID !== this.comData.taskID) {
        return;
      }
      this.execute.on('log', (logs) => {
        this.localLog = this.convertLogs(logs);
        this.script.log = this.localLog.log;
        if (this.scriptViewState.showPanel === 'log') {
          this.localLogShow();
        }
      });
      this.execute.on('result', (ret) => {
        this.showPanelTab('result');
        const storeResult = {
          'headRows': ret.metadata,
          'bodyRows': ret.fileContent,
          'total': ret.totalLine,
          'type': ret.type,
          'cache': {
            offsetX: 0,
            offsetY: 0,
          },
          'path': this.execute.currentResultPath,
          'current': 1,
          'size': 20,
        };
        if (this.execute.resultList[0]) {
          this.$set(this.execute.resultList[0], 'result', storeResult);
        }
        this.$set(this.script, 'resultSet', 0);
        this.script.result = storeResult;
        this.script.resultList = this.execute.resultList;
        this.script.resultSet = 0;
        // 获取过progress的情况下设置为1
        if (this.script.progress.current) {
          this.script.progress.current = 1;
        }
      });
      this.execute.on('progress', ({ progress, progressInfo, waitingSize }) => {
        // 这里progressInfo可能只是个空数组，或者数据第一个数据是一个空对象
        if (progressInfo.length && !isEmpty(progressInfo[0])) {
          progressInfo.forEach((newProgress) => {
            let newId = newProgress.id;
            let index = this.script.progress.progressInfo.findIndex((progress) => {
              return progress.id === newId;
            });
            if (index !== -1) {
              this.script.progress.progressInfo.splice(index, 1, newProgress);
            } else {
              this.script.progress.progressInfo.push(newProgress);
            }
          });
        } else {
          progressInfo = [];
        }

        if (progress == 1) {
          let runningScripts = storage.get(this._running_scripts_key, 'local') || {};
          delete runningScripts[this.script.nodeId];
          storage.set(this._running_scripts_key, runningScripts, 'local');
        }

        this.script.progress.current = progress;

        if (waitingSize !== null && waitingSize >= 0) {
          this.script.progress.waitingSize = waitingSize;
        }
      });
      this.execute.on('steps', (status) => {
        if (this.executeLastStatus === status) {
          return;
        }
        this.executeLastStatus = status;
        if (status === 'Inited') {
          this.script.steps = ['Submitted', 'Inited'];
        } else {
          const lastStep = last(this.script.steps);
          if (this.script.steps.indexOf(status) === -1) {
            this.script.steps.push(status);
            // 针对可能有WaitForRetry状态后，后台会重新推送Scheduled或running状态的时候
          } else if (lastStep !== status) {
            this.script.steps.push(status);
          }
        }
        if (status !== 'Inited' && this.script.steps.length === 1) {
          this.script.steps.unshift('ellipsis');
        }
      });
      this.execute.on('status', (status) => {
        this.script.status = status;
      });
      this.execute.on('querySuccess', ({ type, task }) => {
        const costTime = util.convertTimestamp(task.costTime);
        this.script.progress.costTime = costTime;
        const name = this.script.title;
        this.$Notice.close(name);
        this.$Notice.success({
          title: this.$root.$t('message.common.notice.querySuccess.title'),
          desc: '',
          render: (h) => {
            return h('span', {
              style: {
                'word-break': 'break-all',
                'line-height': '20px',
              },
            }, `${this.script.title} ${type}${this.$root.$t('message.common.notice.querySuccess.render')}：${costTime}！`);
          },
          name,
          duration: 3,
        });
      });
      this.execute.on('notice', ({ type, msg, autoJoin }) => {
        const name = this.script.title;
        const label = autoJoin ? `${this.$root.$t('message.common.script')}${this.script.title} ${msg}` : msg;
        this.$Notice.close(name);
        this.$Notice[type]({
          title: this.$root.$t('message.common.notice.notice.title'),
          name,
          desc: '',
          duration: 5,
          render: (h) => {
            return h('span', {
              style: {
                'word-break': 'break-all',
                'line-height': '20px',
              },
            }, label);
          },
        });
      });
      this.execute.on('costTime', (time) => {
        this.script.progress.costTime = util.convertTimestamp(time);
      });
    },
    resetQuery() {
      this.showPanelTab('progress');
      this.isLogShow = false;
      this.localLog = {
        log: { all: '', error: '', warning: '', info: '' },
        logLine: 1,
      };
      this.script.progress = {
        current: null,
        progressInfo: [],
        waitingSize: null,
        costTime: null,
      };
      this.script.log = { all: '', error: '', warning: '', info: '' };
      this.script.logLine = 1;
      this.script.steps = ['Submitted'];
      this.script.diagnosis = null;
      this.script.result = {
        headRows: [],
        bodyRows: [],
        type: 'EMPTY',
        total: 0,
        path: '',
        cache: {},
      };
      this.script.resultList = null;
    },
    showPanelTab(type) {
      this.scriptViewState.showPanel = type;
      this.script.showPanel = type;
      if (type === 'log') {
        this.localLogShow();
      }
    },
    localLogShow() {
      if (!this.debounceLocalLogShow) {
        this.debounceLocalLogShow = debounce(() => {
          if (this.localLog) {
            this.script.log = Object.freeze({ ...this.localLog.log });
            this.script.logLine = this.localLog.logLine;
          }
        }, 1500);
      }
      this.debounceLocalLogShow();
    },
    openAnalysisTab(type) {
      this.visualShow = type;
      // flage ? this.visualShow = 'table' : this.visualShow = 'visual'
      // this.flage = !this.flage;

      if (type === 'visual') {
        this.biLoading = true;
        let rows = this.scriptResult.headRows;
        let model = {}
        let dates = ["DATE", "DATETIME", "TIMESTAMP", "TIME", "YEAR"]
        let numbers = [
          "TINYINT",
          "SMALLINT",
          "MEDIUMINT",
          "INT",
          "INTEGER",
          "BIGINT",
          "FLOAT",
          "DOUBLE",
          "DOUBLE PRECISION",
          "REAL",
          "DECIMAL",
          "BIT",
          "SERIAL",
          "BOOL",
          "BOOLEAN",
          "DEC",
          "FIXED",
          "NUMERIC"];
        rows.forEach(item=>{
          let sqlType = item.dataType.toUpperCase();
          let visualType = 'string'
          if (numbers.indexOf(sqlType) > -1) {
            visualType = 'number'
          } else if(dates.indexOf(sqlType) > -1) {
            visualType = 'date'
          }
          model[item.columnName] =  {
            sqlType,
            visualType,
            modelType: visualType ==="number" ? "value": "category"
          }
        })
        this.visualParams = {
          // viewId: id,
          // projectId,
          json: {
            name: `${this.script.fileName.replace(/\./g,'')}${this.script.resultSet}`,
            model,
            source: {
              "engineType": "spark", //引擎类型
              "dataSourceType": "resultset", //数据源类型，结果集、脚本、库表
              "dataSourceContent": {
                "resultLocation": this.scriptResult.path
              },
              "creator": "IDE"
            }
          }
        }
      } else if (type === 'dataWrangler') {
        this.dataWranglerParams = {
          simpleMode: true,
          showBottomBar: false,
          importConfig: {
            "dataSourceConfig": {
              "dataSourceType": "linkis",
              "dataSourceOptions": {"taskID": this.work.taskID || this.work.data.history[0].taskID}
            },
            "config": {
              "myConfig": {
                "resultSetPath": [this.scriptResult.path]
              },
              "importConfig": {
                "mergeTables": true,
                "limitRows": 5000,
                "pivotTable": false,
                "tableHeaderRows": 1,
              }
            }
          }
        }
      }
    },
    changeResultSet(data, cb) {
      const resultSet = isUndefined(data.currentSet) ? this.script.resultSet : data.currentSet;
      const findResult = this.script.resultList[resultSet];
      const resultPath = findResult && findResult.path;
      const hasResult = Object.prototype.hasOwnProperty.call(this.script.resultList[resultSet], 'result');
      if (!hasResult) {
        const pageSize = 5000;
        const url = `/${this.getResultUrl}/openFile`;
        let params = {
          path: resultPath,
          pageSize,
        }
        // 如果是api执行需要带上taskId
        if (this.getResultUrl !== 'filesystem') {
          params.taskId = this.comData.taskID
        }
        api.fetch(url, {
          path: resultPath,
          pageSize,
        }, 'get')
          .then((ret) => {
            const result = {
              'headRows': ret.metadata,
              'bodyRows': ret.fileContent,
              // 如果totalLine是null，就显示为0
              'total': ret.totalLine ? ret.totalLine : 0,
              // 如果内容为null,就显示暂无数据
              'type': ret.fileContent ? ret.type : 0,
              'cache': {
                offsetX: 0,
                offsetY: 0,
              },
              'path': resultPath,
              'current': 1,
              'size': 20,
            };
            this.$set(this.script.resultList[resultSet], 'result', result);
            this.$set(this.script, 'resultSet', resultSet);
            this.script.result = result;
            this.script.resultSet = resultSet;
            this.script.showPanel = 'result';
            cb();
          }).catch(() => {
            cb();
          });
      } else {
        this.script.result = this.script.resultList[resultSet].result;
        this.$set(this.script, 'resultSet', resultSet);
        this.script.resultSet = resultSet;
        this.script.showPanel = 'result';
        cb();
      }
    },
    closeConsole() {
      this.$emit('close-console');
    },
    openPanel(type) {
      if (type === 'log') {
        this.isLogShow = true;
        this.showPanelTab(type);
      }
    },
    checkFromCache() {
      // 每次右键控制台，都会创建一个新实例，所以把上一个执行的实例先停掉
      if (this.execute) {
        this.killExecute();
      }
      this.resetQuery();
      this.createScript();
      this.$nextTick(() => {
        this.createExecute(true);
      })
    },
    getLogs() {
      api.fetch(`/entrance/${this.comData.execID}/log`, {
        fromLine: this.fromLine,
        size: -1,
      }, 'get')
        .then((rst) => {
          this.localLog = this.convertLogs(rst.log);
          this.script.log = this.localLog.log;
          this.script.logLine = this.fromLine = rst.fromLine;
          if (this.scriptViewState.showPanel === 'log') {
            this.localLogShow();
          }
        });
    },
    convertLogs(logs) {
      const tmpLogs = this.localLog || {
        log: { all: '', error: '', warning: '', info: '' },
        logLine: 1,
      };
      let hasLogInfo = Array.isArray(logs) ? logs.some((it) => it.length > 0) : logs;
      if (!hasLogInfo) {
        return tmpLogs;
      }
      const convertLogs = util.convertLog(logs);
      Object.keys(convertLogs).forEach((key) => {
        const convertLog = convertLogs[key];
        if (convertLog) {
          tmpLogs.log[key] += convertLog + '\n';
        }
        if (key === 'all') {
          tmpLogs.logLine += convertLog.split('\n').length;
        }
      });
      return tmpLogs;
    }
  }
}
</script>
<style lang="scss" scoped>
@import '@/common/style/variables.scss';
  .log-panel {
    margin-top: 1px;
    border-top: $border-width-base $border-style-base $border-color-base;
    background-color: $background-color-base;
    .workbench-tabs {
      position: $relative;
      height: 100%;
      overflow: hidden;
      box-sizing: border-box;
      z-index: 3;
      .workbench-tab-wrapper {
        display: flex;
        border-top: $border-width-base $border-style-base #dcdcdc;
        border-bottom: $border-width-base $border-style-base #dcdcdc;
        .workbench-tab {
          flex: 1;
          display: flex;
          flex-direction: row;
          flex-wrap: nowrap;
          justify-content: flex-start;
          align-items: flex-start;
          height: 32px;
          background-color: $body-background;
          width: calc(100% - 45px);
          overflow: hidden;
          &.work-list-tab {
            overflow-x: auto;
            overflow-y: hidden;
            &::-webkit-scrollbar {
              width: 0;
              height: 0;
              background-color: transparent;
            }
            .list-group>span {
              white-space: nowrap;
              display: block;
              height: 0;
            }
          }
          .workbench-tab-item {
            text-align: center;
            border-top: none;
            display: inline-block;
            height: 32px;
            line-height: 32px;
            background-color: $background-color-base;
            color: $title-color;
            cursor: pointer;
            min-width: 100px;
            max-width: 200px;
            overflow: hidden;
            margin-right: 2px;
            border: 1px solid #eee;
            &.active {
              margin-top: 1px;
              background-color: $body-background;
              color: $primary-color;
              border-radius: 4px 4px 0 0;
              border: 1px solid $border-color-base;
              border-bottom: 2px solid $primary-color;
            }
          }
        }
        .workbench-tab-control {
            flex: 0 0 45px;
            text-align: right;
            background-color: $body-background;
            border-left: $border-width-base $border-style-base $border-color-split;
            .ivu-icon {
              font-size: $font-size-base;
              margin-top: 8px;
              margin-right: 2px;
              cursor: pointer;
              &:hover {
                  color: $primary-color;
              }
              &.disable {
                  color: $btn-disable-color;
              }
            }
        }
        .workbench-tab-button {
            flex: 0 0 30px;
            text-align: center;
            background-color: $body-background;
            .ivu-icon {
                font-size: $font-size-base;
                margin-top: 8px;
                cursor: pointer;
            }
        }
      }
      .workbench-container {
        height: calc(100% - 36px);
        &.node {
            height: 100%;
        }
        @keyframes ivu-progress-active {
            0% {
                opacity: .3;
                width: 0;
            }
            100% {
                opacity: 0;
                width: 100%;
            }
        }
      }
    }
  }
</style>

